/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef __HMFS_ZONED_H__
#define __HMFS_ZONED_H__

#include <memory>
#include "hmfs_define.h"
#include "device_manager.h"


namespace OHOS::Hmfs {
#define HMFS_ZONED_NONE        0
#define HMFS_ZONED_HA          1
#define HMFS_ZONED_HM          2

typedef int (ReportZonesCb)(int i, void *, void *);

#ifdef HAVE_LINUX_BLKZONED_H

#define HMFS_REPORT_ZONES_BUFSZ    524288
/* Let's just use v2, since v1 should be compatible with v2 */
#define BLK_ZONE_REP_CAPACITY   (1 << 0)

struct BlockZone {
    uint64_t start;          /* Zone start sector */
    uint64_t len;            /* Zone length in number of sectors */
    uint64_t wp;             /* Zone write pointer position */
    uint8_t  type;           /* Zone type */
    uint8_t  cond;           /* Zone condition */
    uint8_t  nonSeq;        /* Non-sequential write resources active */
    uint8_t  reset;          /* Reset write pointer recommended */
    uint8_t  resv[4];
    uint64_t capacity;       /* Zone capacity in number of sectors */
    uint8_t  reserved[24];
};

struct BlockZoneReport {
    uint64_t sector;
    uint32_t nrZones;
    uint32_t flags;
    struct BlockZone zones[0];
};

#define BLK_ZONE_TYPE(z)       (z)->type
#define BLK_ZONE_CONV(z)       ((z)->type == BLK_ZONE_TYPE_CONVENTIONAL)
#define BLK_ZONE_SEQ_REQ(z)    ((z)->type == BLK_ZONE_TYPE_SEQWRITE_REQ)
#define BLK_ZONE_SEQ_PREF(z)   ((z)->type == BLK_ZONE_TYPE_SEQWRITE_PREF)
#define BLK_ZONE_SEQ(z)        (BLK_ZONE_SEQ_REQ(z) || BLK_ZONE_SEQ_PREF(z))
#define BLK_ZONE_COND(z)       (z)->cond

/*
 * Handle kernel zone capacity support
 */
#define BLK_ZONE_EMPTY(z)       (BLK_ZONE_COND(z) == BLK_ZONE_COND_EMPTY)
#define BLK_ZONE_SECTOR(z)      (z)->start
#define BLK_ZONE_LENGTH(z)      (z)->len
#define BLK_ZONE_WP_SECTOR(z)   (z)->wp
#define BLK_ZONE_NEED_RESET(z)  (int)(z)->reset
#define BLK_ZONE_NON_SEQ(z)     (int)(z)->nonSeq
#define BLK_ZONE_CAPACITY(z, f) ((f & BLK_ZONE_REP_CAPACITY) ? (z)->capacity : (z)->len)

struct OneZoneReport {
    BlockZoneReport rep;
    BlockZone zone;
};
#endif
struct BlockZone;

class HmfsZoned {
public:
    static HmfsZoned& GetInstance();
#ifdef HAVE_LINUX_BLKZONED_H
    int GetSysFsPath(std::string& devPath, const std::string& attr, std::string& filePath);
    uint32_t HmfsGetZoneChunkSectors(DeviceInfo *dev);
#endif
    int HmfsResetZones(DeviceInfo *deviceInfo);
    int HmfsGetZonedModel(DeviceInfo *dev);
    int HmfsGetZoneBlocks(DeviceInfo *dev);
    int HmfsCheckZones(DeviceInfo *dev);
    int HmfsResetZone(int i, void *blkzone);
    uint32_t HmfsGetUsableSegments(SuperBlockData *sb);
    int HmfsReportZone(int i, uint64_t sector, BlockZone *blkzone);
    int HmfsReportZones(int j, ReportZonesCb *reportZonesCb, void *opaque);

private:
    HmfsZoned() = default;
#ifdef HAVE_LINUX_BLKZONED_H
    int HmfsCheckZonesPart(DeviceInfo *dev, BlockZoneReport *rep, 
        uint64_t &sector, uint64_t &totalSectors, unsigned int &n);
    const char *BlkZoneTypeStr(BlockZone *blkz);
    const char *BlkZoneCondStr(BlockZone *blkz);
#endif
};
} // namespace OHOS::Hmfs
#endif